﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace Gnosis.Alexandria.Controllers
{
    public abstract class DispatcherBase : IDispatcher
    {
        protected DispatcherBase()
        {    
        }

        protected DispatcherBase(IDispatcher parent)
        {
            _parent = parent;
        }

        private readonly Guid _id = Guid.NewGuid();
        private readonly IDispatcher _parent;
        private readonly IDictionary<Guid, IDispatcher> _children = new Dictionary<Guid, IDispatcher>();

        protected void AddChild(IDispatcher child)
        {
            if (child == null)
                throw new ArgumentNullException("child");

            _children.Add(child.Id, child);
        }

        protected void RemoveChild(Guid handle)
        {
            if (_children.ContainsKey(handle))
                _children.Remove(handle);
        }

        public Guid Id
        {
            get { return _id; }
        }

        private static void HandleIfAppropriate<T>(IDispatcher dispatcher, T message)
            where T : IMessage
        {
            if (!(dispatcher is IHandler<T>))
                return;

            if (message is ITargeted && ((ITargeted)message).Target != dispatcher.Id)
                return;

            ((IHandler<T>)dispatcher).Handle(message);
        }

        public void Dispatch<T>(Guid sender, T message)
            where T : IMessage
        {
            if (_parent != null && sender != _parent.Id)
            {
                HandleIfAppropriate(_parent, message);
                
                _parent.Dispatch<T>(_id, message);
            }

            foreach (var child in _children.Values.Where(x => x.Id != sender))
            {

                HandleIfAppropriate(child, message);

                child.Dispatch<T>(_id, message);
            }
        }
    }
}
